﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	ManagedDisposable.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

#define FREE_ALL_EMPTY

using System;
using System.Diagnostics;

namespace Smart.Common
{
	/// <summary>
	/// Smart disposable reference
	/// </summary>
	[DebuggerStepThrough]
	public class ManagedDisposable<TDisposable> : DisposableBase
		where TDisposable : class, IDisposable
	{
		public ManagedDisposableInfo Info;

		public bool Registered;

		/// <summary>
		/// Smart disposable reference (not saved to cache)
		/// </summary>
		public ManagedDisposable(TDisposable disposable, bool shouldBeDisposed, params object[] args)
		{
			Info = new ManagedDisposableInfo { Disposable = disposable, ShouldBeDisposed = shouldBeDisposed, Args = args };

			Info.IncrementUsage();

			Info.IncrementRef();

			Registered = false;
		}

		/// <summary>
		/// Smart dispose reference (saved to cache)
		/// </summary>
		/// <param name="key">disposable key</param>
		/// <param name="loader">disposable loader</param>
		public ManagedDisposable(string key, Func<ManagedDisposableInfo> loader)
		{
			Info = ManagedDisposableCache.Find(key);

			if (Info == null)
			{
				Info = loader();

				ManagedDisposableCache.Register(Info);
			}

			Info.IncrementUsage();

			Info.IncrementRef();

			Registered = true;
		}

		public TDisposable Disposable
		{
			get { return (TDisposable)Info.Disposable; }
		}

		public static implicit operator TDisposable(ManagedDisposable<TDisposable> src)
		{
			return src.Disposable;
		}

		public static implicit operator ManagedDisposable<TDisposable>(TDisposable src)
		{
			return new ManagedDisposable<TDisposable>(src, true);
		}

		/// <summary>
		/// Dispose managed resources. Method called only once.
		/// </summary>
		protected override void DisposeManaged()
		{
			if (Info == null)
				return;

			if (Registered)
			{
				ManagedDisposableCache.CheckRelease(Info);
			}
			else
			{
				Info.DecrementRef();

				Info.Release();
			}

			Info = null;
		}

		/// <summary>
		/// Dispose unmanaged resources. Method called only once.
		/// </summary>
		protected override void DisposeUnmanaged()
		{
		}
	}
}